#include "g_playerShip.h"

#include "g_shaders.h"

#include <iostream>
#include <fstream>

//Static Members
btAlignedObjectArray<class SpaceShip*> PlayerShip::m_spaceships;

PlayerShip::PlayerShip()
{
	PlayerShip(btVector3(0,0,0));
}

PlayerShip::PlayerShip(btVector3 const & pos): updated(false)
{
	m_ownerWorld = p_dynamicsWorld;
	btScalar size=0.2;
	m_shapes[BODYPART_CHASSIS] = new btBoxShape(btVector3(1*size,1*size,2*size));// btCapsuleShape(btScalar(0.15), btScalar(0.20));

	// Setup all the rigid bodies
	btTransform offset; offset.setIdentity();
	offset.setOrigin(pos);

	btTransform transform;
	transform.setIdentity();
	transform.setOrigin(btVector3(btScalar(0.), btScalar(1.), btScalar(0.)));
	m_bodies[BODYPART_CHASSIS] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_CHASSIS]);

	// Setup some damping on the m_bodies
	for (int i = 0; i < BODYPART_COUNT; ++i){
		m_bodies[i]->setDamping(0.05, 0.85);
		m_bodies[i]->setDeactivationTime(0.8);
		m_bodies[i]->setSleepingThresholds(1.6, 2.5);
	}

	//Graphics init
	loadGeometry("models\\tri_mare.obj");
}

void PlayerShip::loadGeometry(char const * file_name)
{
	ifstream iFile;
	
	int lineCounter = 1;

	iFile.open(file_name, ios::in);
	if (!iFile.good()) cout<<"Error opening file!"<<endl;

		// read header

	string sLine;
	getline(iFile, sLine, '\n');
	lineCounter++;

	getline(iFile, sLine, '\n');
	lineCounter++;

	if (sLine.size() > 0) cout<<"Error reading file!"<<endl;

		// read vertex coordinates

	getline(iFile, sLine, '\n');
	
	while (sLine.substr(0,2) != "vt" && !iFile.eof())
	{
		vector<string> values = break_input(sLine);
		vtx v;
		
		v.x = (float)strtod(values[1].c_str(), NULL);
		v.y = (float)strtod(values[2].c_str(), NULL);
		v.z = (float)strtod(values[3].c_str(), NULL);

		vtx_array.push_back(v);

		lineCounter++;
		getline(iFile, sLine, '\n');
	}
	
		// reading the texture coordinates

	while (sLine.substr(0,2) != "vn" && !iFile.eof())
	{
		vector<string> values = break_input(sLine);
		tex t;

		t.u = (float)strtod(values[1].c_str(), NULL);
		t.v = (float)strtod(values[2].c_str(), NULL);

		tex_array.push_back(t);

		lineCounter++;
		getline(iFile, sLine, '\n');
	}

		// reading the normals

	while (sLine.substr(0,1) != "f" && !iFile.eof())
	{
		vector<string> values = break_input(sLine);
		nml n;

		n.nx = (float)strtod(values[1].c_str(), NULL);
		n.ny = (float)strtod(values[2].c_str(), NULL);
		n.nz = (float)strtod(values[3].c_str(), NULL);
		
		nml_array.push_back(n);
		
		lineCounter++;
		getline(iFile, sLine, '\n');
	}

		//reading the faces
		
	polyCount = 0;

	while (!iFile.eof())
	{
		polyCount++;

		vector<string> values = break_input(sLine);
		vtxData d1, d2, d3;
		unsigned int i1, i2, i3;
		
		i1 = (unsigned int)strtod(values[1].c_str(), NULL) - 1;
		i2 = (unsigned int)strtod(values[4].c_str(), NULL) - 1;
		i3 = (unsigned int)strtod(values[7].c_str(), NULL) - 1;

		d1.x = vtx_array[i1].x; d1.y = vtx_array[i1].y; d1.z = vtx_array[i1].z;
		d2.x = vtx_array[i2].x; d2.y = vtx_array[i2].y; d2.z = vtx_array[i2].z;
		d3.x = vtx_array[i3].x; d3.y = vtx_array[i3].y; d3.z = vtx_array[i3].z;

		i1 = (unsigned int)strtod(values[2].c_str(), NULL) - 1;
		i2 = (unsigned int)strtod(values[5].c_str(), NULL) - 1;
		i3 = (unsigned int)strtod(values[8].c_str(), NULL) - 1;

		d1.u = tex_array[i1].u; d1.v = tex_array[i1].v; 
		d2.u = tex_array[i2].u; d2.v = tex_array[i2].v; 
		d3.u = tex_array[i3].u; d3.v = tex_array[i3].v; 
		
		i1 = (unsigned int)strtod(values[3].c_str(), NULL) - 1;
		i2 = (unsigned int)strtod(values[6].c_str(), NULL) - 1; 
		i3 = (unsigned int)strtod(values[9].c_str(), NULL) - 1;

		d1.nx = nml_array[i1].nx; d1.ny = nml_array[i1].ny; d1.nz = nml_array[i1].nz;
		d2.nx = nml_array[i2].nx; d2.ny = nml_array[i2].ny; d2.nz = nml_array[i2].nz;
		d3.nx = nml_array[i3].nx; d3.ny = nml_array[i3].ny; d3.nz = nml_array[i3].nz;

		data.push_back(d1);
		data.push_back(d2);
		data.push_back(d3);

		lineCounter++;
		getline(iFile, sLine, '\n');
	}
		
	//cout<<"Load file completed successfully...\n";
	//cout<<"Poly Count: "<<face_count<<endl;
	//cout<<"Vertex Count: "<<vtx_array.size()<<endl;

	iFile.close();

	initVBO();
}

vector<string> PlayerShip::break_input(string const & s)
{
	vector<string> sTokens;

	char c;
	bool SPACE = false;
	string sTemp = "";

	for (int i = 0; i < (int)s.length(); i++)
	{
		c = s[i];
		if (c != ' ') SPACE = false;

		if (!SPACE)
		{
			SPACE = false;

			if (!isspace(c)) 
			{
				if (c == '/')
				{
					sTokens.push_back(sTemp);
					sTemp = "";
				}
				else sTemp += c;
			}
			else 
			{
				sTokens.push_back(sTemp);
				sTemp = "";
				SPACE = true;
			}
		}
	}

	if (!SPACE) sTokens.push_back(sTemp);

	return sTokens;
}

void PlayerShip::initVBO()
{
	glGenBuffers(1, &vboID);
	glBindBuffer(GL_ARRAY_BUFFER, vboID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vtxData) * data.size(), &data[0].x, GL_STATIC_DRAW);

	//map vertex coordinates to array index 0
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vtxData), 0);

	//map normal coordinates to array index 1
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vtxData), OFFSET(12));

	//map texture coordinates to array index 2
	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vtxData), OFFSET(24));
}

void PlayerShip::drawGeometry(GLuint render_mode)
{
	if (render_mode == 0) glUseProgram(shaders::phong_shader);
	if (render_mode == 1) glUseProgram(shaders::lambert_shader);
	
	glBindBuffer(GL_ARRAY_BUFFER, vboID);
	
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();

		//glTranslatef(pos[0], pos[1], pos[2]);
		//glRotatef(rotation, 0, 1, 0);
		glDrawArrays(GL_TRIANGLES, 0, data.size());

	glPopMatrix();
}

PlayerShip::~PlayerShip() {}

void PlayerShip::setObjectState(int state)
{
	isActive = (state==ACTIVE_STATE)?ACTIVE_STATE:IN_ACTIVE_STATE;
	pgObjectsMap.insert(make_pair(TYPEID_SPACESHIP,this));
		
	for (int i = 0; i < BODYPART_COUNT; ++i){
		p_dynamicsWorld->addRigidBody(m_bodies[i]);
	}

	//for(int i = 0; i < JOINT_COUNT; i++){
	//	p_dynamicsWorld->addConstraint(m_joints[i], true);
	//}
}

void PlayerShip::deleteAllSpaceShips(){
	for (int i=0;i<m_spaceships.size();i++){
		SpaceShip* ship = m_spaceships[i];
		delete ship;
	}
}